import type { PromptRequest } from '@stagewise/extension-toolbar-srpc-contract';
import { AnalyticsService, EventName } from 'src/services/analytics-service';
import {
  AgentStateType,
  createAgentServer,
  type UserMessage,
  type AgentServer,
  type UserMessageContentItem,
  type SelectedElement,
} from '@stagewise/agent-interface/agent';
import * as vscode from 'vscode';
import { dispatchAgentCall } from 'src/utils/dispatch-agent-call';

// Timeout constants for agent state transitions
const AGENT_COMPLETION_DELAY_MS = 1000;
const AGENT_IDLE_DELAY_MS = 5000;
const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath ?? '';

export class AgentService {
  private static instance: AgentService;
  private analyticsService: AnalyticsService = AnalyticsService.getInstance();
  private server: AgentServer | null = null;

  private constructor() {
    // Private constructor to enforce singleton pattern
  }

  public shutdown() {
    this.server?.server.close();
  }

  public static getInstance(): AgentService {
    if (!AgentService.instance) {
      AgentService.instance = new AgentService();
    }
    return AgentService.instance;
  }

  public async initialize() {
    console.log('🚀 [AgentService] 开始初始化...');
    this.server = await createAgentServer();
    console.log('✅ [AgentService] Agent Server 创建成功');

    this.server.setAgentName(vscode.env.appName);
    this.server.setAgentDescription(
      vscode.workspace.name ?? 'No open workspace',
    );
    this.server.interface.availability.set(true);
    console.log('✅ [AgentService] Agent 配置完成，已设置为可用状态');

    let timeoutHandler: NodeJS.Timeout | null = null;
    this.server.interface.messaging.addUserMessageListener((message) => {
      console.log('📨 [AgentService] 收到用户消息:', message);
      this.server?.interface.state.set(AgentStateType.WORKING);
      const promptContentItems = message.contentItems.filter(
        ({ type }) => type === 'image' || type === 'text',
      );

      const questionContentItems = message.contentItems
        .filter(({ type, text }: any) => type === 'text' && text.length > 0)
        .map((item: any) => {
          return {
            type: 'text',
            text: item.text,
          };
        });

      if (questionContentItems.length) {
        this.server?.interface.messaging.addPart({
          type: 'text',
          text: `您的输入为:${JSON.stringify(message, null, 2)}`,
        });

        this.triggerAgentPrompt(message);
      }

      // 粘贴到剪切板动作
      if (promptContentItems.length) {
        this.triggerAllAgentPrompt(message);
        if (timeoutHandler) {
          clearTimeout(timeoutHandler);
        }
        timeoutHandler = this.scheduleStateTransitions();
      }
    });
    console.log('✅ [AgentService] 消息监听器已添加');
  }

  private async triggerAllAgentPrompt(userMessage: UserMessage) {
    // Create the nice prompt that we need
    this.analyticsService.trackEvent(EventName.AGENT_PROMPT_TRIGGERED);
    const request: PromptRequest = {
      prompt: createPrompt(userMessage),
    };
    //  这个是原来调用方法，复制相应文件
    await dispatchAgentCall(request);
  }

  private scheduleStateTransitions(): NodeJS.Timeout {
    return setTimeout(() => {
      this.server?.interface.state.set(
        AgentStateType.COMPLETED,
        'Prompt was added to the agents chatbox',
      );
      // 不再自动转换到 IDLE，让用户可以继续查看结果
      // this.scheduleIdleTransition();
    }, AGENT_COMPLETION_DELAY_MS);
  }

  private scheduleIdleTransition(): void {
    setTimeout(() => {
      this.server?.interface.state.set(AgentStateType.IDLE);
    }, AGENT_IDLE_DELAY_MS);
  }

  private async triggerAgentPrompt(userMessage: UserMessage) {
    console.log('🎯 [AgentService] triggerAgentPrompt 被调用');
    console.log(
      '📝 [AgentService] 用户消息内容:',
      JSON.stringify(userMessage, null, 2),
    );

    // Create the nice prompt that we need
    this.analyticsService.trackEvent(EventName.AGENT_PROMPT_TRIGGERED);

    const request: PromptRequest = {
      prompt: createPrompt(userMessage),
    };

    console.log('🚀 [AgentService] 开始调用 Qwen Agent...');
    // 使用流式 AI 回复展示
    await this.triggerQwenAgentStream(userMessage, request);
  }

  /**
   * 流式处理 Qwen Agent 响应并在 toolbar 中实时展示
   */
  private async triggerQwenAgentStream(
    userMessage: UserMessage,
    request: PromptRequest,
  ) {
    const API_ENDPOINT = 'http://localhost:3008/chat';

    // 1. 显示用户输入
    this.server?.interface.messaging.addPart({
      type: 'text',
      text: `📝 您的输入:\n${userMessage.contentItems
        .filter((item) => item.type === 'text')
        .map((item) => (item as { type: 'text'; text: string }).text)
        .join('\n')}`,
    });

    // 2. 准备流式响应的累积文本
    const aiResponsePart: any = {
      type: 'text',
      text: '🤖 AI 回复: ',
    };

    // 添加初始 AI 响应 part，并记录索引
    this.server?.interface.messaging.addPart(aiResponsePart);
    const allParts = this.server?.interface.messaging.get() || [];
    const aiPartIndex = allParts.length - 1;

    console.log(
      `[DEBUG] AI part added at index: ${aiPartIndex}, total parts: ${allParts.length}`,
    );

    try {
      // 3. 构建请求
      const requestBody = {
        message: request.prompt,
        model: 'qwen3-coder-plus',
        tools: true,
        stream: true,
        workspaceRoots: workspaceRoot,
      };

      // 4. 发送请求
      const response = await fetch(API_ENDPOINT, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(requestBody),
      });

      if (!response.ok) {
        throw new Error(
          `API 请求失败: ${response.status} ${response.statusText}`,
        );
      }

      if (!response.body) {
        throw new Error('响应体为空');
      }

      // 5. 处理 SSE 流
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      let toolCallCount = 0;

      while (true) {
        const { done, value } = await reader.read();

        if (done) {
          break;
        }

        const chunk = decoder.decode(value, { stream: true });
        const lines = chunk.split('\n');

        let currentEventType = '';

        for (const line of lines) {
          // 解析 SSE 事件
          if (line.startsWith('event: ')) {
            currentEventType = line.slice(7).trim();
            continue;
          }

          if (line.startsWith('data: ')) {
            try {
              const data = JSON.parse(line.slice(6));

              // 跳过 finished 事件（包含 finishReason，不需要显示）
              if (currentEventType === 'finished') {
                continue;
              }

              // 处理不同类型的事件
              if (data.data && typeof data.data === 'string') {
                // content 事件 - 累积文本
                aiResponsePart.text += data.data;

                // 更新 toolbar 中的 AI 回复
                // 每次都从 messaging 系统获取最新的 parts 数组，确保索引正确
                const currentParts =
                  this.server?.interface.messaging.get() || [];
                const currentAiPart = currentParts[aiPartIndex];

                if (currentAiPart && currentAiPart.type === 'text') {
                  // 更新实际的 part 对象
                  currentAiPart.text = aiResponsePart.text;
                  this.server?.interface.messaging.updatePart(
                    currentAiPart,
                    aiPartIndex,
                    'replace',
                  );
                } else {
                  console.warn(
                    `[DEBUG] AI part at index ${aiPartIndex} not found or wrong type. Total parts: ${currentParts.length}`,
                  );
                }
              } else if (data.data && data.data.name) {
                // toolCallRequest 事件 - 显示工具调用
                toolCallCount++;
                this.server?.interface.messaging.addPart({
                  type: 'text',
                  text: `🔧 执行工具 #${toolCallCount}: ${data.data.name}`,
                });
                console.log(
                  `[DEBUG] Added tool call part, new total parts: ${(this.server?.interface.messaging.get() || []).length}`,
                );
              } else if (data.result) {
                // toolCallCompleted 事件 - 显示工具执行结果
                this.server?.interface.messaging.addPart({
                  type: 'text',
                  text: `✅ 工具执行完成`,
                });
              } else if (data.error) {
                // error 事件
                this.server?.interface.messaging.addPart({
                  type: 'text',
                  text: `❌ 错误: ${data.error}`,
                });
              }
            } catch (parseError) {
              console.warn('解析 SSE 数据失败:', parseError);
            }
          }
        }
      }

      // 6. 添加完成标记
      this.server?.interface.messaging.addPart({
        type: 'text',
        text: `✨ AI 处理完成！${toolCallCount > 0 ? `执行了 ${toolCallCount} 个工具操作` : ''}`,
      });
    } catch (error: any) {
      console.error('Qwen Agent 流式处理错误:', error);

      // 显示错误信息
      this.server?.interface.messaging.addPart({
        type: 'text',
        text: `❌ AI 处理失败: ${error.message || '未知错误'}\n提示: 请确保 Qwen API 服务器正在运行 (http://localhost:3008)`,
      });
    }
  }
}

/**
 * Generates a detailed context string for a single HTMLElement.
 */
function generateElementContext(
  element: SelectedElement,
  isParent = false,
): string {
  const nodeType = element.nodeType || 'UNKNOWN';
  const attributes = element.attributes || {};
  const properties = element.ownProperties || {};

  // Get file location before filtering properties
  const fileLocation = getFileLocation(element);

  // For parent elements, don't include properties at all
  const filteredProperties = isParent
    ? {}
    : Object.entries(properties)
        .filter(([key]) => {
          // Filter out React internal properties and debug properties
          if (/^_*react/i.test(key) || key.indexOf('debug') !== -1) {
            return false;
          }
          return true;
        })
        .reduce((acc, [key, value]) => {
          acc[key] = value;
          return acc;
        }, {} as any);

  const boundingRect = element.boundingClientRect || {};
  const textContent = element.textContent || '';
  const pluginInfo = element.pluginInfo || '';
  const xpath = element.xpath || '';
  const parent = element.parent || null;

  return `
<node_type>${nodeType}</node_type>
<attributes>
${Object.entries(attributes)
  .map(([key, value]) => `<${key}>${value}</${key}>`)
  .join('\n')}
</attributes>
${
  !isParent
    ? `<properties>
${Object.entries(filteredProperties)
  .map(([key, value]) => `<${key}>${JSON.stringify(value)}</${key}>`)
  .join('\n')}
</properties>`
    : ''
}
<bounding_client_rect>
<width>${boundingRect.width || 0}</width>
<height>${boundingRect.height || 0}</height>
<top>${boundingRect.top || 0}</top>
<left>${boundingRect.left || 0}</left>
</bounding_client_rect> 
<text_content>
${textContent}
</text_content>
<plugin_info>
${pluginInfo}
</plugin_info>
<xpath>${xpath}</xpath>

${!isParent ? `<file_location>${fileLocation}</file_location>` : ''}
${
  parent && !isParent
    ? `<parent>
${generateElementContext(parent, true)}
</parent>`
    : ''
}
`.trim();
}

/**
 * Creates a comprehensive prompt for a Coding Agent LLM.
 *
 * @param selectedElements - An array of HTMLElements the user interacted with.
 * @param userPrompt - The user's natural language instruction.
 * @param url - The URL of the page where the interaction occurred.
 * @param contextSnippets - An array of context snippets from a list of plugins.
 * @returns A formatted string prompt for the LLM.
 */
export function createPrompt(msg: UserMessage): string {
  const pluginContext = Object.entries(msg.pluginContent)
    .map(
      ([pluginName, snippets]) =>
        [
          pluginName,
          Object.entries(snippets).filter(
            ([_, snippet]) => snippet.type === 'text',
          ),
        ] as [string, [string, UserMessageContentItem][]],
    )
    .filter(([_, snippets]) => snippets.length > 0)
    .map(([pluginName, snippets]) => {
      return `
<plugin_contexts>
<${pluginName}>
${snippets.map((snippet) => `<${snippet[0]}>${(snippet[1] as { type: 'text'; text: string }).text}</${snippet[0]}>`).join('\n')}
</${pluginName}>
</plugin_contexts>
`.trim();
    })
    .join('\n');

  const userMessage = msg.contentItems
    .filter((item) => item.type === 'text')
    .map((item) => (item as { type: 'text'; text: string }).text)
    .join('\n\n');

  return `
<request>
<user_message>${userMessage}</user_message>
  <url>${msg.metadata.currentUrl}</url>
  <pageTitle>${msg.metadata.currentTitle}</pageTitle>
  <browser_locale>${msg.metadata.locale}</browser_locale>
  <user_agent>${msg.metadata.userAgent}</user_agent>
  ${
    msg.metadata.selectedElements.length > 0
      ? `<selected_elements>
    ${msg.metadata.selectedElements.map((element, index) => `<element_${index}>${generateElementContext(element)}</element_${index}>`).join('\n')}
  </selected_elements>`
      : ''
  }
  ${pluginContext}
</request>`.trim();
}

// Add helper function to get file location
function getFileLocation(element: any): string {
  try {
    // 检查 properties 中的 React Fiber 属性（数据实际在这里）
    const properties = element.ownProperties || {};

    // 查找 React Fiber 属性 - 使用更灵活的匹配
    const propKeys = Object.keys(properties);
    const reactFiberKeys = propKeys.filter(
      (key) =>
        /^_*reactFiber\$/i.test(key) || key.indexOf('reactFiber$') !== -1,
    );

    for (const fiberKey of reactFiberKeys) {
      try {
        // properties 中的数据是 JSON 字符串，需要解析
        const fiberData =
          typeof properties[fiberKey] === 'string'
            ? JSON.parse(properties[fiberKey])
            : properties[fiberKey];

        if (fiberData && fiberData._debugSource) {
          const source = fiberData._debugSource;
          if (source.fileName && source.lineNumber !== undefined) {
            return `${source.fileName}:${source.lineNumber}:${source.columnNumber || 0}`;
          }
        }
      } catch (parseError) {
        console.log(`Failed to parse fiber data for ${fiberKey}:`, parseError);
      }
    }

    return '';
  } catch (error) {
    console.error('Error in getFileLocation:', error);
    return '';
  }
}
